#include <pvm3.h>

#include "job.h"
#include <string.h>
#include <math.h>

#define NB_JOB 400
// convertit un nombre en base 10 EN BASE 26, puis ajoute 1 à chacun des chiffres en base 26 -> base 27
unsigned long incremente(unsigned long nb)
{
  unsigned long mine = 0;;
  int k=0;
  // conversion en base 26
  while(nb!=0)
    {
      mine += pow((double) 10,(double) k)*(nb%26);
      //printf("mine : %lu\n",mine);
      nb = (nb-(nb%26))/26;
      k++;
    }
  int size = log10(mine)+1;
  //printf("b_26 : %lu\n",mine);
  //printf("size : %d\n",size);
  int j;
  unsigned long add=0;
    // on augmente de 1 tous les chiffres
  for(j=0;j<size;j++)
    {
      add+=pow((double)10,(double)j);
    }
  //printf("add  : %lu\n",add);
  return add+mine;  
}

struct job * get_job(unsigned long max)
{
  static unsigned long current_job = 0;
  
  if(current_job == NB_JOB)
    {
      printf("no more jobs");
      return NULL;
    }
  else
    {
      struct job * new_job = malloc(sizeof(struct job));
      new_job->init = current_job*max/NB_JOB;
      new_job->end = (current_job+1)*max/NB_JOB;
      incremente(new_job->init);
      incremente(new_job->end);
      current_job++;
      return new_job;
    }
} 

char *convert(unsigned long deb)
{
  char * str1 = malloc(sizeof(char)*size_max);
  char * str2 = malloc(sizeof(char)*(size_max+1));

  unsigned long res = deb;
  unsigned long aux;
  char *a = malloc(sizeof(char)*size_max);
  int k=0;
  while(deb!=0)
    {
      aux = (deb)%27;
      a[0] = 'a' + aux - 1;
      a[1]='\0';
      deb = (deb-aux)/27;
      strcat(str1,a);
      k++;
    }

int i;
  for (i=0;i<k;i++)
    str2[i]=str1[k-i-1];
  str2[k] = '\0';
  return str2;

}


void * waiting_loop(void * A)
{
 
  while (1)
    {
      struct job * new_job = get_job(pow(26,size_max));
      if (new_job == NULL)
	{
	  return NULL;
	}
      char * str1 = convert(new_job->init);
      char * str2 = convert(new_job->end);
      int bufid = pvm_recv(-1,-1);
      int bytes,msgtag,tid;
      pvm_bufinfo(bufid,&bytes,&msgtag,&tid);
      if (msgtag == 1)
	{
	  pvm_initsend(PvmDataDefault);
	  strcat(str1," ");
	  strcat(str1,str2);
	  pvm_pkstr(str1);
	  pvm_send(tid,1);
	}
      else
	{
	  if (msgtag == 2)
	    {
	      printf("Le processus n°%d a trouvé le mdp\n",tid);  
	      int i;
	      for (i=0;i<nb_slave;i++)
		{
		  pvm_kill(tids[i]);
		}
	      res = 1;
	      return NULL;
	    }
	}
    }
  return NULL;
}


int master(char *password)
{
  char buf[atoi(size_max)];
  int buf_id,tag,slave_id;
  tids = malloc(nb_slave*sizeof(int));
  pvm_initsend(PvmDataDefault);
  pthread_t waiting_thread;

  argv[0]=password;
  argv[1]=size_max;
  argv[2]=NULL;


  if(pvm_spawn("slave", argv, PvmTaskDefault, "", nb_slave, tids)<nb_slave)
    {
      printf("spawn foireux\n");
    }
  int i;
  int max = pow(26,size_max);
  for (i=0;i<nb_slave;++i)
    {
      struct job * job_sent = get_job(max);
      if (job_sent == NULL)
	{
	  printf("caca");
	  break;
	}
      char * str1 = convert(job_sent->init);
      char * str2 = convert(job_sent->end);
      strcat(str1," ");
      strcat(str1,str2);
      pvm_pkstr(str1);
      pvm_send(tid[i],1);
    }
  
  pthread_create(&waiting_thread,NULL,waiting_loop,NULL);
  
  pthread_join(waiting_thread,NULL);
  if (res != 1)
    {
      printf("Password not found");
    }
  return EXIT_SUCCESS;
}


int main(int argc,char*argv[])
{
*  if(argc < 3){
    printf("expected slave_nbr|password|size_max\n");
    return 0;
  }
  
  nb_slave = atoi(argv[1]);
  size_max = atoi(argv[3]);
  
  master(argv[2]);
  return EXIT_SUCCESS;
}
